package com.vision.sales.deliveryreceipt.cl.ui;

import static com.vision.sales.cl.SalesServices.salesInvoiceSvc;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.editor.client.SimpleBeanEditorDriver;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.widget.core.client.Window;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.event.HideEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.form.DateField;
import com.sencha.gxt.widget.core.client.form.NumberField;
import com.sencha.gxt.widget.core.client.form.NumberPropertyEditor;
import com.sencha.gxt.widget.core.client.form.SimpleComboBox;
import com.sencha.gxt.widget.core.client.form.TextArea;
import com.sencha.gxt.widget.core.client.form.TextField;
import com.sencha.gxt.widget.core.client.form.validator.MaxLengthValidator;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GridView;
import com.vision.core.cl.BaseModule;
import com.vision.core.cl.Callback;
import com.vision.core.cl.ui.ConfirmDialogHandler;
import com.vision.core.cl.ui.Notifications;
import com.vision.core.cl.ui.UI;
import com.vision.core.cl.ui.component.BasicGridView;
import com.vision.core.cl.ui.component.CompanyComboBox;
import com.vision.core.cl.ui.component.CompanyGroupComboBox;
import com.vision.core.cl.ui.component.EnumComboBox;
import com.vision.core.cm.db.data.CompanyGroup;
import com.vision.core.cm.util.DateUtils;
import com.vision.sales.cl.data.DeliveryReceiptProperties;
import com.vision.sales.cl.event.SalesInvoiceCreatedEvent;
import com.vision.sales.cl.resource.SalesResources;
import com.vision.sales.cl.ui.component.ProductComboBox;
import com.vision.sales.cm.data.CollectionStatus;
import com.vision.sales.cm.db.data.Customer;
import com.vision.sales.cm.db.data.DeliveryReceipt;
import com.vision.sales.cm.db.data.SalesInvoice;
import com.vision.sales.cm.db.data.SalesInvoice.FieldSpecs;
import com.vision.sales.cm.db.data.Salesman;

/**
 * 
 * @author Mark
 *
 */
public class InvoiceReceiptsWindow implements IsWidget, Editor<SalesInvoice> {
	
	interface Binder extends UiBinder<Widget, InvoiceReceiptsWindow> { }
	
	private static final Binder binder = GWT.create(Binder.class);
	
	@UiField Window window;
	
	// Form fields that are bound by the form driver to the fields in the Customer class.
	// The name of these form fields must match the name of the field in the Customer class. 
	@UiField CompanyComboBox company;
	@UiField CompanyGroupComboBox group;
	@UiField TextField invoiceNo;
	@UiField DateField date;
	@UiField TextField poNo;
	@Ignore @UiField TextField customerTxt;
	@Ignore @UiField TextField salesmanTxt;
	
	@Ignore @UiField(provided = true) NumberPropertyEditor<Double> doublePropertyEditor = UI.doubleEditor();
	@Ignore @UiField(provided = true) NumberFormat numberFormat = UI.amountFormat();
	@UiField NumberField<Double> grossSales;
	
	@UiField ProductComboBox product;
	
	@UiField TextArea remarks;
	@UiField TextArea itemsDelivered;
	
	@UiField Grid<DeliveryReceipt> deliveryReceiptsGrid;
	
	@Ignore @UiField TextButton saveBtn;
	@Ignore @UiField TextButton cancelBtn;
	
	interface SalesInvoiceDriver extends SimpleBeanEditorDriver<SalesInvoice, InvoiceReceiptsWindow> { }
	
	private SalesInvoiceDriver driver = GWT.create(SalesInvoiceDriver.class);
	
	Customer customer;
	Salesman salesman;
	List<DeliveryReceipt> deliveryReceipts;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public InvoiceReceiptsWindow(Customer customer, Salesman salesman, List<DeliveryReceipt> deliveryReceipts) {
		this.customer = customer;
		this.salesman = salesman;
		this.deliveryReceipts = deliveryReceipts;
	}
	
	@Override
	public Widget asWidget() {
		window = (Window) binder.createAndBindUi(this);
		window.getHeader().setIcon(SalesResources.INSTANCE.salesInvoices());
		
		driver.initialize(this);
		driver.edit(new SalesInvoice(new Timestamp(System.currentTimeMillis())));
		
		date.setPropertyEditor(UI.datePropertyEditor());
		date.setValue(new Date());
		
		invoiceNo.addValidator(new MaxLengthValidator(FieldSpecs.INVOICE_NO_MAX));
		poNo.addValidator(new MaxLengthValidator(FieldSpecs.PO_NO_MAX));
		itemsDelivered.addValidator(new MaxLengthValidator(FieldSpecs.ITEMS_DELIVERED_MAX));
		remarks.addValidator(new MaxLengthValidator(FieldSpecs.REMARKS_MAX));
		
		loadData();
		
		customerTxt.setText(customer == null ? "--" : customer.getCode());
		salesmanTxt.setText(salesman == null ? "--" : salesman.getCode());
		
		if (deliveryReceipts != null) {
			deliveryReceiptsGrid.getStore().addAll(deliveryReceipts);
		}
		
		return window;
	}
	
	// UiFactory Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Ignore
	@UiFactory
	SimpleComboBox<CollectionStatus> initializeCollectionStatusCombo() {
		return new EnumComboBox<CollectionStatus>(CollectionStatus.values());
	}
	
	@UiFactory
	Grid<DeliveryReceipt> initializeGrid() {
		DeliveryReceiptProperties props = DeliveryReceiptProperties.INSTANCE;
		
		List<ColumnConfig<DeliveryReceipt, ?>> columns = new ArrayList<ColumnConfig<DeliveryReceipt, ?>>();
		
		columns.add(UI.column(props.date(), 80, "D/R Date", UI.dateCell()));
		columns.add(UI.column(props.drNo(), 80, "D/R No."));
		columns.add(UI.column(props.remarks(), 320, "Remarks"));
		
		ColumnModel<DeliveryReceipt> cm = new ColumnModel<DeliveryReceipt>(columns);

		Grid<DeliveryReceipt> grid = new Grid<DeliveryReceipt>(new ListStore<DeliveryReceipt>(props.key()), cm);
		grid.setAllowTextSelection(false);
		
		GridView<DeliveryReceipt> view = new BasicGridView<DeliveryReceipt>();
		view.setEmptyText("There are no delivery receipts to display.");
		view.setAutoExpandColumn(columns.get(columns.size() - 1));
		grid.setView(view);
		
		return grid;
	}
	
	// UiHandlers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	@UiHandler("group")
	void groupChanged(SelectionEvent<CompanyGroup> e) {
		CompanyGroup group = e.getSelectedItem();
		company.setValue(group.getCompany());
	}
	
	@UiHandler("saveBtn")
	void saveClicked(SelectEvent e) {
		final SalesInvoice invoice = driver.flush();
		if (driver.hasErrors())
			return;
		
		if (deliveryReceipts == null || deliveryReceipts.isEmpty()) {
			Notifications.info("There are no delivery receipts.");
			return;
		}
		
		for (DeliveryReceipt dr : deliveryReceipts) {
			if (DateUtils.isAfter(dr.getDate(), invoice.getDate())) {
				Notifications.info("One of the delivery receipts has a date later than the sales invoice's");
				return;
			}
		}
		
		invoice.setCompany(invoice.getGroup().getCompany());
		
		if (invoice.getGrossSales() == 0D) {
			UI.confirm("Zero Gross Sales", "The gross sales amount is zero. Do you wish to continue?", new ConfirmDialogHandler() {
				@Override
				public void onYes(HideEvent event) {
					doTheSave(invoice);
				}
			});
		} else {
			doTheSave(invoice);
		}
	}
	
	@UiHandler("cancelBtn")
	void cancelClicked(SelectEvent e) {
		window.hide(cancelBtn);
	}
	
	// Logic %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	public void loadData() {
		Log.debug("Loading salesmen, companies, customers, products for dropdown...");
		
		UI.mask(company, "Loading companies...");
		company.loadCompanies();
		
		UI.mask(group, "Loading groups...");
		group.loadGroups();
		
		UI.mask(product, "Loading products...");
		product.loadProducts();
	}
	
	void doTheSave(final SalesInvoice invoice) {
		invoice.setCollectionStatus(CollectionStatus.UNPAID);
		
		invoice.setCustomer(customer);
		invoice.setSalesman(salesman);
		invoice.setDeliveryReceipts(new HashSet<DeliveryReceipt>(deliveryReceipts));
		
		UI.mask(window, "Creating sales invoice...");
		salesInvoiceSvc().create(invoice, new Callback<SalesInvoice>(window) {
			@Override
			protected void handleSuccess(SalesInvoice result) {
				window.hide(saveBtn);
				BaseModule.fireEvent(new SalesInvoiceCreatedEvent(result));
			}
		});
	}

}
